package WebGamble;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.awt.BorderLayout;
import javax.swing.JPanel;

public class PCEggsSim extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static String BaseURL = "http://www.pceggs.com/play/pg28Insert.aspx?LID=";
	static Random rand = new Random();

	static private HttpResponse httpResponse;
	static private DefaultHttpClient httpClient = new DefaultHttpClient();
	static public class showImg extends JPanel {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		JLabel jl = null;
		ImageIcon img = null;

		public showImg(InputStream bmpFile) throws IOException {
			img = new ImageIcon(ImageIO.read(bmpFile));
			jl = new JLabel(img);
			this.setLayout(new BorderLayout());
			this.add(jl, BorderLayout.CENTER);
		}
	}
	
	static public int GCD(int numA, int numB) {
		int gcd = 1;
		for (int k = 1; k <= numA && k <= numB; k++)
			if (numA % k == 0 && numB % k == 0)
				gcd = k;
		return gcd;
	}
	
	static public double min(double[] valList) {
		double val;
		val = valList[0];
		for(double value : valList) {
			if(value < val)
				val = value;
		}
		return val;
	}
	static public int MinLoc(double[] valList) {
		double val;
		val = valList[0];
		int i = 0, loc = 0;
		for(double value : valList) {
			if(value < val) {
				val = value;
				loc = i;
			}
			i++;
		}
		return loc;
	}
	
	static public double max(double[] valList) {
		double val;
		val = valList[0];
		for(double value : valList) {
			if(value > val)
				val = value;
		}
		return val;
	}
	
	static public int sum(int[] valList) {
		int val = 0;
		for(int value : valList)
			val += value;
		return val;
	}
	static public double sum(double[] valList) {
		double val = 0;
		for(double value : valList)
			val += value;
		return val;
	}
	
	static public double score1(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double count = 0;
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = oddsList[i] * distribution[i] - s;
			if(score[i] < 0)
				count += originDist[i];
		}
		return min(score) - count * 2;
	}
	static public int[] originDist = {1, 3, 6, 10, 15, 21, 28, 72, 90, 110, 126, 138, 146, 150, 150, 146, 138, 126, 110, 90, 72, 28, 21, 15, 10, 6, 3, 1};
//	static public int[] originDist = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 63, 69, 73, 75, 75, 73, 69, 63, 55, 45, 36, 28, 21, 15, 10, 6, 3, 1};
	static public double total = sum(originDist);
	static public double score2(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double count = 0;
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s) * originDist[i];
			if(score[i] < 0)
				count += 1;
		}
		return sum(score) / total - count;
	}
	static public double score3(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s) * originDist[i];
		}
		return sum(score) / total;
	}
	
	static public void optimize(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s);
		}
		int loc;
		loc = MinLoc(score);
		distribution[loc]++;
		for(int i = 0; i < 28; i++) {
			if(score[i] >= 0 && score[i] <= 7) {
				distribution[i]++;
			}
		}
	}
	
	static public int[] baseDist = {2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2};
	
	static public int[] getNextDist(int[] distribution) {
		int[] nextDist = distribution.clone();
		int t = rand.nextInt(22) + 1;
		for(; t > 0; t--) {
			while(true) {
				int i = rand.nextInt(22) + 3;
				int step = 1;
				double flag = rand.nextDouble();
				if(flag < 0.5)
					step = -1;
				int temp = nextDist[i] + step; 
				if(temp >= baseDist[i]) {
					nextDist[i] = temp;
					break;
				}
			}
		}
		return nextDist;
	}
	static public int[] getNextDist0(int[] distribution) {
		int[] nextDist = distribution.clone();
		while(true) {
			int i = rand.nextInt(28);
			int step = 1;
			int temp = nextDist[i] + step; 
			if(temp >= baseDist[i]) {
				nextDist[i] = temp;
				break;
			}
		}
		return nextDist;
	}
	
	static public int showStatus(double[] oddsList, int[] distribution, int idx, boolean showFlag) {
		double[] score = new double[28];
		int s = sum(distribution);
		int count = 0;
		if(showFlag) {
			System.out.println(idx + "th step:");
			for(int i = 0; i < 28; i++) {
				System.out.printf("%d: %03d, ", i, distribution[i]);
			}
			System.out.println();
		}
		for(int i = 0; i < 28; i++) {
			score[i] = oddsList[i] * distribution[i] - s;
			if(score[i] < 0)
				count++;
			if(showFlag)
				System.out.printf("%d: %06f, ", i, score[i]);
		}
		if(showFlag) {
			System.out.println();
			System.out.println("Total negative: " + count);
			System.out.println("Min: " + min(score));
			System.out.println("Max: " + max(score));
			for(int i = 0; i < 28; i++)
				score[i] = score[i] * originDist[i];
			System.out.println("Avg: " + sum(score) / total);
			System.out.println("Num: " + s);
		}
		return count;
	}
	
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException {
		
        
        int originTimes = 1, timesOfTimes = 8;
        int money = 0, prevMoney = 0, times = originTimes;
        int winCount = 0, loseCount = 0;
        int topCount = 0;
        int positive = 0, negative = 0;
        int simCount;
        int sumRes = 5000;
        
        FileReader fr1 = new FileReader(new File("D:\\lab\\gamble\\OddsTrain.log"));
        FileReader fr2 = new FileReader(new File("D:\\lab\\gamble\\OddsTest.log"));
        BufferedReader br1 = new BufferedReader(fr1);
        BufferedReader br2 = new BufferedReader(fr2);
        
        for(simCount = 0; simCount < 600; simCount++) {

            int i;
            
            double[] oddsList = new double[28];
            double[] realOddsList = new double[28];
            String train = br1.readLine();
            String test = br2.readLine();
            StringTokenizer tk1 = new StringTokenizer(train);
            StringTokenizer tk2 = new StringTokenizer(test);
            tk1.nextToken(); tk2.nextToken();
            for(i = 0; i < 28; i++) {
            	oddsList[i] = Double.parseDouble(tk1.nextToken()) *98 / 100;
            	realOddsList[i] = Double.parseDouble(tk2.nextToken());
            }
            int a, b, c, simVal, result;
            simVal = Integer.parseInt(tk2.nextToken());
            
            String odds;

            money = sumRes;

            times = 1;
	       
//            System.out.println("Current times: " + times);
            prevMoney = money;
            
            

            int looperLimit = 8;
            int[] finalDist = new int[28];
            double finalScore = -8, finalCount = 28;
            
            for(int looper = 0; looper < looperLimit; looper++) {
           	 //int[] distribution = {1, 1, 1, 1, 1, 1, 2, 5, 5, 5, 25, 25, 25, 25, 25, 25, 25, 25, 5, 5, 5, 2, 1, 1, 1, 1, 1, 1};
               int[] distribution = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
               double T, dE, r;
               T = sum(oddsList) * sum(distribution);
               r = 0.9;
               i = 0;
               int[] nextDist;
               int score = showStatus(oddsList, distribution, i, false), nextScore = 0;
               int countFlag = 0;
               while (countFlag < 5 || i < 4000) {
	       			nextDist = getNextDist(distribution);
//	       			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
	       			dE = score2(oddsList, nextDist) - score2(oddsList, distribution);
	       			nextScore = showStatus(oddsList, distribution, i, false);
	       			if (dE > 0 && nextScore <= score) {
	
	       				distribution = nextDist.clone(); 
	       			}
	       			else {
	
	       				if (Math.exp(dE / T) > rand.nextDouble() * 3) {
	       					distribution = nextDist.clone();
	       					optimize(oddsList, distribution);
	       				}
	       					
	       			}
	       			
	       			if(score2(oddsList, nextDist) > finalScore/* && nextScore <= finalCount + 1*/ && nextScore <= 8) {
        				finalScore = score2(oddsList, nextDist);
        				finalCount = nextScore;
        				finalDist = nextDist.clone();
        				showStatus(oddsList, finalDist, i, false);
        			}
	       			
	       			T = r * T;
	       			i++;
	       			
	       			
	       			if(nextScore == score)
	       				countFlag++;
	       			else
	       				countFlag = 0;
	       			score = nextScore;
	       		}
               
           }
            
            if((!(score3(oddsList, finalDist) < 4) && !(finalCount >= 9)) || (!(score3(oddsList, finalDist) < 1) && !(finalCount >= 7))) {
            	for(i = 0; i < 28; i++) {
                	finalDist[i] *= times;
                }

                result = (int) (finalDist[simVal] * realOddsList[simVal] - sum(finalDist));
                sumRes += result;
                System.out.println("result: " + result + ", " + sumRes + ", " + times + ", " + sum(finalDist) + ", " + score3(oddsList, finalDist) + ", " + finalCount);
                
                showStatus(oddsList, finalDist, 0, false);
//                System.out.println();
//                System.out.println("Running time: " + (endT - startT) / 1000 + "s");
//                System.out.println("Current ID: " + gambleId);
//                Thread.sleep(50000);
            }
        }
        fr1.close();
        fr2.close();
	}
}
